iT邦幫忙

2022 iThome 鐵人賽

DAY 7
0
自我挑戰組

挑戰typescript+react+golang+graphql系列 第 7

Day7. sync.Mutex, Channel

  • 分享至 

  • xImage
  •  

Mutex

先用一個例子開頭,大家猜猜最後value會是多少?

package main

import (
	"fmt"
	"sync"
)

var x = 0

func increment(wg *sync.WaitGroup) {
	x = x + 1
	wg.Done()
}
func main() {
	var w sync.WaitGroup
	for i := 0; i < 1000; i++ {
		w.Add(1)
		go increment(&w)
	}
	w.Wait()
	fmt.Println("final value of x", x)
}

看起來是1000,但在IDE上執行會發現幾乎都是9XX
為什麼會造成這種情況呢?
答案是Race condiction
https://ithelp.ithome.com.tw/upload/images/20220920/20150497on58aLOqgF.png

如圖所示,當兩個goroutine同時去操縱x的時候,導致x只被加了一次,因此結果會小於正確的 1000。

為了避免race condiction,我們可以使用sync.Mutex上鎖,官網上說:This concept is called mutual exclusion, and the conventional name for the data structure that provides it is mutex.

維基百科介紹:
互斥鎖(英語:Mutual exclusion,縮寫Mutex)是一種用於多執行緒編程中,防止兩條執行緒同時對同一公共資源(比如全域變數)進行讀寫的機制。

所以使用mutex可以避免race condiction,我們把程式修改如下:

package main  
import (  
    "fmt"
    "sync"
    )
var x  = 0  
func increment(wg *sync.WaitGroup, m *sync.Mutex) {  
    m.Lock()
    x = x + 1
    m.Unlock()
    wg.Done()   
}
func main() {  
    var w sync.WaitGroup
    var m sync.Mutex
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go increment(&w, &m)
    }
    w.Wait()
    fmt.Println("final value of x", x)
}

Channel

Go還有一個特別的地方就是可以利用Channel傳值,如果說 goroutine 是 Go語言程式的併發體的話,那麼 channels 就是它們之間的通信機制。一個 channels 是一個通信機制,它可以讓一個 goroutine 通過它給另一個 goroutine 發送值信息。每個 channel 都有一個型別,也就是 channels 可發送數據的類型。一個可以發送 int 類型數據的 channel 一般寫為 chan int。

package main

import (  
    "fmt"
)

func hello(done chan bool) {  
    fmt.Println("Hello world goroutine")
    done <- true
}
func main() {  
    done := make(chan bool)
    go hello(done)
    <-done
    fmt.Println("main function")
}

// Hello world goroutine
    main function

可以看到透過channel的方式回傳了Hello world goroutine

channel也可以搭配range跟close來使用

package main

import "fmt"

func main() {
	percentageChannel := make(chan int)
	go updatePercentage(percentageChannel)
	for i := range percentageChannel {
		fmt.Println(i)
        
        // 當i == 100時關閉channel
		if i == 100 {
			close(percentageChannel)
			break
		}
	}
}

func updatePercentage(channel chan int) {
	for i := 1; i <= 100; i++ {
		channel <- i
	}
}

上一篇
Day6. Goroutine, sync.WaitGroup
下一篇
Day8
系列文
挑戰typescript+react+golang+graphql18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言